﻿using HamcoWcs.Models.DbInfos;
using HamcoWcs.Models.PlcInfos;
using HslCommunication.Profinet.Melsec;
using Snap7;
using System;
using System.Collections.Generic;

namespace HamcoWcs.Models.Devices
{
    public abstract class PlcBase<T> where T : class, new()
    {
        //public Action BeforeConnect { get; set; }
        //public Action AfterConnect { get; set; }
        //public Action BeforeDisconnect { get; set; }
        //public Action AfterDisconnect { get; set; }

        public object DeviceLock { get; set; } = new object();

        protected int ReadErrorTimes = 0;

        public PlcBase(string plcName, PlcInfoDto plcInfo, List<DbInfoDto> dbInfo)
        {
            Client = new T();
            PlcName = plcName;
            PlcInfo = plcInfo;
            DbInfo = dbInfo;
        }

        /// <summary>
        /// PLC名
        /// </summary>
        public string PlcName { get; set; }

        /// <summary>
        /// DB块信息
        /// </summary>
        public List<DbInfoDto> DbInfo { get; set; }
        /// <summary>
        /// 连接PLC客户端
        /// </summary>
        public T Client { get; set; }
        /// <summary>
        /// PLC信息，入IP，端口等
        /// </summary>
        public PlcInfoDto PlcInfo { get; set; }
        /// <summary>
        /// 连接状态
        /// </summary>
        public bool ConnectionStatus { get; set; }
        /// <summary>
        /// 连接到PLC
        /// </summary>
        public abstract void ConnectToPlc();
        /// <summary>
        /// 断开Plc连接
        /// </summary>
        public abstract void DisconnectToPlc();


        protected virtual void OnBeforeConnect()
        {

        }
        protected virtual void OnAfterConnect()
        {

        }

        protected virtual void OnBeforeDisconnect()
        {

        }

        protected virtual void OnAfterDisconnect()
        {

        }
    }


    /// <summary>
    /// S7协议的西门子PLC
    /// </summary>
    public abstract class SiemensPlc : PlcBase<S7Client>
    {
        protected SiemensPlc(string plcName, PlcInfoDto plcInfo, List<DbInfoDto> dbInfo) : base(plcName, plcInfo, dbInfo)
        {
        }

        public override void ConnectToPlc()
        {
            OnBeforeConnect();
            int connectRe = this.Client.ConnectTo(this.PlcInfo.PlcIp, 0, 1);
            this.ConnectionStatus = connectRe == 0;
            OnAfterConnect();
        }

        public override void DisconnectToPlc()
        {
            OnBeforeDisconnect();
            this.ConnectionStatus = false;
            this.Client.Disconnect();
            OnAfterDisconnect();
        }
    }

    /// <summary>
    /// MC协议类型的三菱PLC
    /// </summary>
    public abstract class MitsubishiPlc : PlcBase<MelsecMcNet>
    {
        protected MitsubishiPlc(string plcName, PlcInfoDto plcInfo, List<DbInfoDto> dbInfo) : base(plcName, plcInfo, dbInfo)
        {
        }

        public override void ConnectToPlc()
        {
            OnBeforeConnect();
            this.Client.IpAddress = this.PlcInfo.PlcIp;
            this.Client.Port = int.Parse(this.PlcInfo.PlcPort);
            //this.Client.ConnectTimeOut = 3000;
            var connectRe = this.Client.ConnectServer();
            this.ConnectionStatus = connectRe.IsSuccess;
            OnAfterConnect();
        }

        public override void DisconnectToPlc()
        {
            OnBeforeDisconnect();
            this.Client.ConnectClose();
            this.ConnectionStatus = false;
            OnAfterDisconnect();
        }

    }

    public sealed class PlcCommunicationException : Exception
    {
        public PlcCommunicationException(string message) : base(message)
        {
        }
    }
}

